﻿/** Copyright © 2010-2015 Vahid Jalili
 * 
 * This file is part of ReShapes project.
 * ReShapes is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation,
 * either version 3 of the License, or (at your option) any later version.
 * ReShapes is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along with Foobar. If not, see http://www.gnu.org/licenses/.
 **/

using System;
using System.Collections.Generic;

namespace ReShapes
{
    class Reasoning_Engine
    {
        public int
            Difference_between_fig_A_and_fig_B = 0,
            Neighbors = 0,
            Figure_A_meets_Count = 0,
            Figure_B_meets_Count = 0,
            Upsilon = 10,
            Lambda = 10,
            Omega = 3,
            d = 2;

        private int
            max_x = 0, max_y = 0,
            rotation_Angle,
            reasoning_level;


        public double
            Desired_Percesion = 0.0;

        public List<Iteration> Iterations = new List<Iteration>();       

        public List<List<bool>> Figure_A = new List<List<bool>>();
        public List<List<bool>> Figure_B = new List<List<bool>>();


        private List<List<int>> Figure_B_meets = new List<List<int>>();
        private List<List<int>> Figure_A_meets = new List<List<int>>();


        private int[,] Fig_A_Crop = new int[,] { { -1, -1 }, { -1, -1 } };
        private int[,] Fig_B_Crop = new int[,] { { -1, -1 }, { -1, -1 } };


        public List<List<int[]>> Matches = new List<List<int[]>>();


        public int Rotation_Angle
        {
            get { return rotation_Angle; }
            set
            {
                if (rotation_Angle != value)
                {
                    rotation_Angle = value;
                    OnRotation_AngleValueChaned(value);
                }
            }
        }
        public event EventHandler<ValueEventArgs> Rotation_AngleValueChanged;
        private void OnRotation_AngleValueChaned(int value)
        {
            if (Rotation_AngleValueChanged != null)
                Rotation_AngleValueChanged(this, new ValueEventArgs(value));
        }


        public int Reasoning_Level
        {
            get { return reasoning_level; }
            set
            {
                if (reasoning_level != value)
                {
                    reasoning_level = value;
                    Reasonig_Level_changed(value);
                }
            }
        }
        public event EventHandler<ValueEventArgs> Reasoning_Level_in_Process;
        private void Reasonig_Level_changed(int value)
        {
            if (Reasoning_Level_in_Process != null)
                Reasoning_Level_in_Process(this, new ValueEventArgs(value));
        }


        public void Run_Reasoning()
        {
            Reasoning_Level = 0;
            Iterations.Clear();

            bool Initial_Phase = true;

            max_x = Figure_A.Count;
            max_y = Figure_A[0].Count;

            Setup_Fig_A_Crop();
            Setup_Figure_A_meets();

            Setup_Fig_B_Crop();
            Setup_Figure_B_meets();

            Setup_Matches();

            Difference_between_fig_A_and_fig_B = Calculate_Diffrence_between_FigA_n_FigB();

            for (int l = Omega; l <= Math.Ceiling(Math.Log((360 / Desired_Percesion), 2)); l++)
            {
                Reasoning_Level = l;

                Iterations.Add(new Iteration());

                if (!Initial_Phase)
                    Make_Alpha_set(l - Omega);

                Iterations[l - Omega].Figure_A_meets = Figure_A_meets;
                Iterations[l - Omega].Figure_B_meets = Figure_B_meets;
                //Iterations[l - Omega].d = (int)Math.Floor(d / Math.Pow(2, l - Omega)); 
                Iterations[l - Omega].Figure_A_Crop = Fig_A_Crop;
                Iterations[l - Omega].Figure_B_Crop = Fig_B_Crop;
                Iterations[l - Omega].LN = l;
                Iterations[l - Omega].LM = l;
                Iterations[l - Omega].Lambda = Lambda;
                Iterations[l - Omega].Omega = Omega;

                switch (Neighbors)
                {
                    case -1: // Akin to Iteration
                        Iterations[l - Omega].Neighbor_Range = l - Omega;
                        break;

                    case 0: // Don't consider the neighbors
                        Iterations[l - Omega].Neighbor_Range = 0;
                        break;

                    default: // a constant distance of neighbors
                        Iterations[l - Omega].Neighbor_Range = Neighbors;
                        break;
                }

                Iterations[l - Omega].Start_Reasoning(Initial_Phase);
                Initial_Phase = false;
            }

            Reasoning_Level = 1000000;
        }


        private void Setup_Figure_A_meets()
        {
            Figure_A_meets.Clear();

            int
                X_Center = (int)Math.Round((Fig_A_Crop[1, 0] - Fig_A_Crop[0, 0]) / 2.0) + Fig_A_Crop[0, 0],
                Y_Center = (int)Math.Round((Fig_A_Crop[1, 1] - Fig_A_Crop[0, 1]) / 2.0) + Fig_A_Crop[0, 1];


            for (int x = 0; x < max_x; x++)
                for (int y = 0; y < max_y; y++)
                    if (Figure_A[x][y] == true)
                    {
                        List<int> t = new List<int>();
                        
                        t.Add(x - X_Center);
                        t.Add(Y_Center - y);

                        Figure_A_meets.Add(t);
                    }

            Figure_A_meets_Count = Figure_A_meets.Count;
        }
        private void Setup_Figure_B_meets()
        {
            Figure_B_meets.Clear();

            int
                X_Center = (int)Math.Round((Fig_B_Crop[1, 0] - Fig_B_Crop[0, 0]) / 2.0) + Fig_B_Crop[0, 0],
                Y_Center = (int)Math.Round((Fig_B_Crop[1, 1] - Fig_B_Crop[0, 1]) / 2.0) + Fig_B_Crop[0, 1];


            for (int x = 0; x < max_x; x++)
                for (int y = 0; y < max_y; y++)
                    if (Figure_B[x][y] == true)
                    {
                        List<int> t = new List<int>();

                        t.Add(x - X_Center);
                        t.Add(Y_Center - y);

                        Figure_B_meets.Add(t);
                    }

            Figure_B_meets_Count = Figure_B_meets.Count;
        }


        private void Setup_Matches()
        {
            Matches.Clear();
            for (int i = 0; i < 101; i++)
            {
                List<int[]> t = new List<int[]>();
                Matches.Add(t);
            }
        }


        private void Setup_Fig_A_Crop()
        {
            bool ini_case = true;
            for (int x = 0; x < max_x; x++)
                for (int y = 0; y < max_y; y++)
                    if (Figure_A[x][y] == true)
                    {
                        switch (ini_case)
                        {
                            case true:
                                Fig_A_Crop[0, 0] = x;
                                Fig_A_Crop[1, 0] = x;
                                Fig_A_Crop[0, 1] = y;
                                Fig_A_Crop[1, 1] = y;
                                break;

                            case false:
                                if (x < Fig_A_Crop[0, 0])
                                    Fig_A_Crop[0, 0] = x;
                                else
                                    if (x > Fig_A_Crop[1, 0])
                                        Fig_A_Crop[1, 0] = x;

                                if (y < Fig_A_Crop[0, 1])
                                    Fig_A_Crop[0, 1] = y;
                                else
                                    if (y > Fig_A_Crop[1, 1])
                                        Fig_A_Crop[1, 1] = y;
                                break;
                        }
                        ini_case = false;
                    }
        }
        private void Setup_Fig_B_Crop()
        {
            bool ini_case = true;
            for (int x = 0; x < max_x; x++)
                for (int y = 0; y < max_y; y++)
                    if (Figure_B[x][y] == true)
                    {
                        switch (ini_case)
                        {
                            case true:
                                Fig_B_Crop[0, 0] = x;
                                Fig_B_Crop[1, 0] = x;
                                Fig_B_Crop[0, 1] = y;
                                Fig_B_Crop[1, 1] = y;
                                break;

                            case false:
                                if (x < Fig_B_Crop[0, 0])
                                    Fig_B_Crop[0, 0] = x;
                                else
                                    if (x > Fig_B_Crop[1, 0])
                                        Fig_B_Crop[1, 0] = x;

                                if (y < Fig_B_Crop[0, 1])
                                    Fig_B_Crop[0, 1] = y;
                                else
                                    if (y > Fig_B_Crop[1, 1])
                                        Fig_B_Crop[1, 1] = y;
                                break;
                        }
                        ini_case = false;
                    }
        }
        private int Calculate_Diffrence_between_FigA_n_FigB()
        {
            int D = 0;

            if (Figure_A_meets.Count < Figure_B_meets.Count)
            {
                int
                X_Center = (int)Math.Round((Fig_A_Crop[1, 0] - Fig_A_Crop[0, 0]) / 2.0) + Fig_A_Crop[0, 0],
                Y_Center = (int)Math.Round((Fig_A_Crop[1, 1] - Fig_A_Crop[0, 1]) / 2.0) + Fig_A_Crop[0, 1];

                for (int i = 0; i < Figure_A_meets.Count; i++)
                    if (Figure_B[Figure_A_meets[i][0] + X_Center][(Figure_A_meets[i][1] * (-1)) + Y_Center] == true)
                        D++;

                D = Figure_B_meets.Count - D;
            }
            else
            {
                int
                X_Center = (int)Math.Round((Fig_B_Crop[1, 0] - Fig_B_Crop[0, 0]) / 2.0) + Fig_B_Crop[0, 0],
                Y_Center = (int)Math.Round((Fig_B_Crop[1, 1] - Fig_B_Crop[0, 1]) / 2.0) + Fig_B_Crop[0, 1];

                for (int i = 0; i < Figure_B_meets.Count; i++)
                    if (Figure_A[Figure_B_meets[i][0] + X_Center][(Figure_B_meets[i][1] * (-1)) + Y_Center] == true)
                        D++;
                D = Figure_A_meets.Count - D;
            }

            return D;
        }


        private void Generate_Reasoning_Result()
        {
            for (int i = 0; i < 360; i++)
            {
                int[] A = new int[4];

                /*
                A[3] = 
                    L1_Overall_Results[i, 1] +
                    L2_Overall_Results[i, 1] +
                    L3_Overall_Results[i, 1] +
                    L4_Overall_Results[i, 1];*/

                /*
                if (A[3] > 0)
                {
                    A[2] =
                        L1_Overall_Results[i, 2] +
                        L2_Overall_Results[i, 2] +
                        L3_Overall_Results[i, 2] +
                        L4_Overall_Results[i, 2];

                    A[0] = i;

                    A[1] =
                        Math.Max(
                        Math.Max(L1_Overall_Results[i, 0], L2_Overall_Results[i, 0]),
                        Math.Max(L3_Overall_Results[i, 0], L4_Overall_Results[i, 0]));

                    Reasoning_Results.Add(A);
                }*/
            }

            //Reasoning_Results.Sort(Compare_R);
        }
        private int Compare_R(int[] A, int[] B)
        {
            return B[3].CompareTo(A[3]);
        }
        

        private void Make_Alpha_set(int Iteration_Index)
        {
            Iterations[Iteration_Index].Alpha.Clear();
            //int Number_of_Added_Transformations = 0;

            for (int i = 0; i < Upsilon; i++)
                if (Iterations[Iteration_Index - 1].Results.Count > i)
                {
                    Iterations[Iteration_Index].Alpha.Add(Iterations[Iteration_Index - 1].Results[i].C_Shitfs);
                }
                else
                {
                    i = Upsilon;
                }

            /*
            for (int i = 100; i >= 0; i--)
            {
                for (int j = 0; j < Iterations[Iteration_Index - 1].Matches[i].Count; j++)
                {
                    Number_of_Added_Transformations++;

                    if (Number_of_Added_Transformations <= Upsilon)
                        Iterations[Iteration_Index].Alpha.Add((int)Iterations[Iteration_Index - 1].Matches[i][j][1]);
                    else
                    {
                        j = Iterations[Iteration_Index - 1].Matches[i].Count;
                        i = 0;
                    }
                }
            }*/
        }
    }
}
